package org.clockwise.util;

import java.util.Arrays;

import org.clockwise.multimethod.SRW;

public class MyMath {

	public static double EPSILON = 0.000001;
	public static int ROUND = 200;

	public static double product(double[] a, double[] b) {
		if (a.length != b.length) {
			System.out.println("Fatal Error! Vector dimentions are not match!");
			return 0;
		}
		double sum = 0.0;
		for (int i = 0; i < a.length; i++) {
			sum += a[i] * b[i];
		}
		return sum;
	}

	public static double[] calEigen(double[][] matrix, double[] init,
			double epsilon) {

		// check the dimension of matrix and initial vector
		int dim = matrix.length;
		if (init.length != dim) {
			System.out
					.println("Fatal Error! Dimension of matrix and vector are not match!");
			return null;
		}
		for (int i = 0; i < dim; i++) {
			if (matrix[i].length != dim) {
				System.out.println("Fatal Error! The matrix is not square!");
				return null;
			}
		}

		double[] vector = Arrays.copyOf(init, init.length);
		double[] temp = Arrays.copyOf(init, init.length);
		epsilon *= epsilon;
		boolean isDone = false;
		double delta = 0.0, sum = 0.0;
		int round = 0;
		while (round < MyMath.ROUND && !isDone) {
			delta = 0.0;
			for (int i = 0; i < dim; i++) {
				sum = 0.0;
				for (int j = 0; j < dim; j++) {
					sum += matrix[i][j] * vector[j];
				}
				temp[i] = sum;
				delta += (temp[i] - vector[i]) * (temp[i] - vector[i]);
			}
			for (int i = 0; i < dim; i++) {
				vector[i] = temp[i];
			}
			if (delta <= epsilon) {
				isDone = true;
			}
			round++;
		}
		System.out.println("Round " + round);
		return vector;
	}
	
	private static final int MAX_ROUND = 200;

	public static double[] eigenvector(double[][] matrix, double[] init,
			double epsilon) {

		epsilon *= epsilon;

		if (matrix.length != init.length) {
			System.out.println("Error! Dimension not match!");
			return null;
		}

		int dim = init.length;
		double[] v = Arrays.copyOf(init, dim);
		double[] t = Arrays.copyOf(v, v.length);
		double delta = 0.0, sum = 0.0;
		int round = 0;
		boolean isDone = false;
		while (!isDone && round < MAX_ROUND) {
			delta = 0.0;
			for (int i = 0; i < dim; i++) {
				sum = 0;
				for (int j = 0; j < dim; j++) {
					sum += v[j] * matrix[j][i];
				}
				t[i] = sum;
				delta += (t[i] - v[i]) * (t[i] - v[i]);
			}

			for (int i = 0; i < dim; i++) {
				v[i] = t[i];
			}

			if (delta <= epsilon) {
				isDone = true;
			}
			round++;
		}

		if (round == MAX_ROUND) {
			System.out.println("Warning: PageRank may not converge");
//			MyMath.printMatrix(matrix);
//			System.out.println(MyStrUtil.getLineSeparator());
//			MyMath.printVector(v);
//			System.out.println(MyStrUtil.getLineSeparator());
		}
		// System.out.print("\tround: " + round + "\t");
		return v;
	}

	public static void printVector(double[] vector) {
		for (int i = 0; i < vector.length; i++) {
			if (i != 0)
				System.out.print("\t");
			System.out.print(vector[i]);
		}
		System.out.println("");
	}

	public static void printMatrix(double[][] matrix) {

		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				System.out.print(matrix[i][j] + "\t");
			}
			System.out.println("");
		}
	}
	
	public static boolean almostEqual(double[] a, double[] b) {
		assert (a.length == b.length);
		double sum = 0.0;
		for (int i = 0; i < a.length; i++) {
			sum += Math.abs(a[i] - b[i]);
		}
		return sum <= EPSILON;
	}
	
	public static boolean almostEqual(double[][] a, double[][] b) {
		assert (a.length == b.length);
		for (int i = 0; i < a.length; i++) {
			assert (a[i].length == b[i].length);
			double sum = 0.0;
			for (int j = 0; j < a[i].length; j++) {
				sum += Math.abs(a[i][j] - b[i][j]);
			}
			if (sum > EPSILON) {
				return false;
			}
		}
		return true;
	}
	public static double[][] getRidOfEpsilon(double[][] matrix) {
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				if (matrix[i][j] < EPSILON) {
					matrix[i][j] = 0.0;
				}
			}
		}
		return matrix;
	}
	
}